%%%-------------------------------------------------------------------
%%% File    : cluster.erl
%%% Author  :  vjache
%%% Description : 
%%%
%%% Created :  2 Feb 2010 by  vjache
%%%-------------------------------------------------------------------
-module(cluster).

-include("../../include/cluster.hrl").

-behaviour(supervisor).

%% API
-export([start_link/1,
		 advertise/2,
		 sup_name/1,
		 sup_name/2,
		 srv_name/2,
		 evt_mgr_name/2,
		 srv_name/1,
		 evt_mgr_name/1,
		 descriptor/1,
		 get_names/1,
		 get_names/2,
		 fold_names/3,
		 add_listener/3,
		 add_listenera/2,
		 add_listenert/3,
		 add_sup_listener/3,
		 add_sup_listenera/2,
		 add_sup_listenert/3,
		 whereis/2]).

%% Supervisor callbacks
-export([init/1]).

%% --------------------------------------------------------------------
%% Macros
%% --------------------------------------------------------------------
-define(SERVER, ?MODULE).

%%====================================================================
%% API functions
%%====================================================================
%%--------------------------------------------------------------------
%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
%% Description: Starts the supervisor
%%--------------------------------------------------------------------
start_link(ClusterName) ->
    Res=supervisor:start_link(sup_name(ClusterName), ?MODULE, [ClusterName]),
	Res.

advertise(ClusterName,Advert) ->
	Pid=self(),
	advertise(ClusterName,Pid,Advert).

advertise(ClusterName,Pid,Advert) ->
	case global:register_name(
		   #global_name{cluster=ClusterName,advert=Advert}, 
		   Pid) of
		yes -> yes;
		no -> no
	end.
whereis(ClusterName,Advert)->
	global:whereis_name(#global_name{cluster=ClusterName,advert=Advert}).

sup_name(ClusterName,Node) ->
	{global,#global_name{cluster=sys_clust,advert={Node,cluster_sup,ClusterName}}}.
sup_name(ClusterName) ->
	sup_name(ClusterName,node()).
srv_name(ClusterName,Node) ->
	{global,#global_name{cluster=sys_clust,advert={Node,cluster_srv,ClusterName}}}.
srv_name(ClusterName) ->
	srv_name(ClusterName,node()).
evt_mgr_name(ClusterName,Node) ->
	{global,#global_name{cluster=sys_clust,advert={Node,cluster_evt_mgr,ClusterName}}}.
evt_mgr_name(ClusterName) ->
	evt_mgr_name(ClusterName,node()).

descriptor(ClusterName) 
  when is_atom(ClusterName) ->
	#cluster{name=ClusterName,
			 filter_fun=fun(#global_name{cluster=C,advert=_})->
								C==ClusterName;
						   (_)->
								false
						end}.

get_names(ClusterName) ->
	srv_call(ClusterName,get_names).
get_names(ClusterName,PredFun) 
  when is_function(PredFun, 1) ->
	srv_call(ClusterName,{get_names,PredFun}).
fold_names(ClusterName,FoldFun,Acc0) 
	when is_function(FoldFun, 2) ->
	srv_call(ClusterName,{get_names,FoldFun,Acc0}).
add_listenera(ClusterName,ActionFun) when is_function(ActionFun,1) ->
	gen_event:add_handler(evt_mgr_name(ClusterName), cluster_listener, [{action,ActionFun}]).
add_listenert(ClusterName,TranFun,State0) when is_function(TranFun,2) ->
	gen_event:add_handler(evt_mgr_name(ClusterName), cluster_listener, [{transition,TranFun,State0}]).
add_listener(ClusterName,Module,Args) when is_list(Args),is_atom(Module) ->
	gen_event:add_handler(evt_mgr_name(ClusterName), Module, Args).

add_sup_listenera(ClusterName,ActionFun) when is_function(ActionFun,1) ->
	gen_event:add_sup_handler(evt_mgr_name(ClusterName), cluster_listener, [{action,ActionFun}]).
add_sup_listenert(ClusterName,TranFun,State0) when is_function(TranFun,2) ->
	gen_event:add_sup_handler(evt_mgr_name(ClusterName), cluster_listener, [{transition,TranFun,State0}]).
add_sup_listener(ClusterName,Module,Args) when is_list(Args),is_atom(Module) ->
	gen_event:add_sup_handler(evt_mgr_name(ClusterName), Module, Args).

%%====================================================================
%% Supervisor callbacks
%%====================================================================
%%--------------------------------------------------------------------
%% Func: init(Args) -> {ok,  {SupFlags,  [ChildSpec]}} |
%%                     ignore                          |
%%                     {error, Reason}
%% Description: Whenever a supervisor is started using 
%% supervisor:start_link/[2,3], this function is called by the new process 
%% to find out about restart strategy, maximum restart frequency and child 
%% specifications.
%%--------------------------------------------------------------------
init([ClusterName]) ->
	%% 	advertise(ClusterName,self(),cluster_gname(ClusterName)),
	SrvModule=cluster_srv,
	EvtMgrRef=evt_mgr_name(ClusterName),
	Srv = {srv,{SrvModule,start_link,[descriptor(ClusterName),5000,EvtMgrRef]},
		   permanent,2000,worker,[SrvModule]},
	Evt = {evt,
		   {gen_event, start_link, [EvtMgrRef]},
		   permanent, 5000, worker, dynamic},
	{ok,{{one_for_all,0,1}, [Evt,Srv]}}.

%%====================================================================
%% Internal functions
%%====================================================================
srv_call(ClusterName,Request) ->
	case gen_server:call(srv_name(ClusterName), Request) of
		{error,Reason} ->
			throw(Reason);
		Result ->
			Result
	end.